﻿
declare function escape(s: string): string;
declare function unescape(s: string): string;

interface ILoginSet {
    inputId: string,
    inputPwd: string,
    ckRember: string,
    btnLogin: string,
    cookiesName: string,
    path: string,
    controller: string;
}
interface ITHead {
    name: string;
    class?: string;
    width?: number;
    toString(): string;
}
interface JQuery {
    /**
     * 导出Excel
     * @param option 
     * @returns {} 
     */
    Table2Excel(option: any): JQuery;
    /**
     * 日期段
     * @returns {} 
     */
    DateSwitch(): JQuery;
    /**
     * 
     * @param args 
     * @returns {} 
     */
    datetimepicker(...args: any[]): JQuery;
    /**
     * 
     * @param args 
     * @returns {} 
     */
    bootstrapSwitch(...args: any[]): JQuery;
    /**
     * 
     * @returns {} 
     */
    tooltip(): JQuery;
    /**
     * 
     * @param args 
     * @returns {} 
     */
    modal(...args: any[]): JQuery;
    /**
     * 
     * @param param 
     * @returns {} 
     */
    validationEngine(...args: any[]): boolean;

    /**
     * 
     * @param args 
     * @returns {} 
     */
    ajaxAddOptions(...args: any[]): JQuery;

    /**
     * 
     * @param args 
     * @returns {} 
     */
    AddOptions(...args: any[]): JQuery;


    /**
     * 表单初始化
     */
    initForm(): JQuery;
    /**
     * 重置表单
     */
    ResetForm(): JQuery;
    /**
     * 根据标题生成表头
     * @param {type} heads 标题数组
     */
    MakeHead(heads: Array<ITHead>): JQuery;

    /**
     * 定义日期插件
     */
    SetDate(): JQuery;
    /**
     * 定义时间插件
     */
    SetDateTime(): JQuery;


    /**
     * 获取html标签名称
     */
    tagName(): string;
    /**
     * 获取json对象
     */
    GetJson(): Object;

    /**
     * 关闭自定义的弹窗
     */
    closeModal(): JQuery;

    /**
     * 兼容bootstrap的自定义弹窗(或许在微信端用)
     * @param {string} o? 如果为'hide'则隐藏弹窗，否则显示弹窗
     */
    myModal(o?: string): JQuery;

    /**
     * 获得双向绑定工具
     * @param {type} o?
     */
    ItemBinder(o?: Object): Sail.Binder;
    /**
     * 表单验证
     */
    CheckValidation(): boolean;
    /**
     * 回车触发按钮
     * @param {any} btn
     */
    EnterToClick(btn: any): JQuery;
    /**
     * 给表格中空白td增加一个&nbsp;
     */
    TableChange(): JQuery;

    /**
     * 读取远程模板文件
     */
    loadRemoteTmpl(): JQuery;

    /**
     * 根据模板和数据输出html
     * @param {string} tmpl
     * @param {any} data
     */
    Render(tmpl: string, data: any): JQuery
    /**
     * 根据模板和数据绑定html
     * @param {string} tmpl
     * @param {any} data
     */
    Link(tmpl: string, data: any): JQuery;
    /**
     * 表单对象的val转换为int 如果转换失败则为0
     */
    valToInt(): number;
    /**
     * 把表单对象的val转换为float 如果转换失败则为0
     */
    valToFloat(): number;
    /**
     * 设置元素显示或隐藏
     * @param {type} isshow
     */
    Display(isshow: boolean): JQuery;
    /**
     * 给table增加合计行 根据thead的第一行th数量生成对应的td数量
     * @param {type} cols 需合计的列
     * @param {type} title 合计行的名称，默认为:合计
     * @param {type} skipStep 每隔n行计算一次，默认为每行都计算
     */
    AddSum(cols: Array<number>, title: string, skipStep: number): JQuery;
};

declare function WdatePicker(param: any): any;

module Sail {





    //取val的int形式
    $.fn.valToInt = function (): number {
        var val = $(this).val();
        if (!val) return 0;
        var x = parseInt(val);
        if (isNaN(x)) x = 0;
        return x;
    }
    //取val的float形式
    $.fn.valToFloat = function (): number {
        var val = $(this).val();
        if (!val) return 0;
        var x = parseFloat(val);
        if (isNaN(x)) x = 0;
        return x;
    }
    ///给tbody增加合计行，skipStep可以指定每隔几行计算一次
    $.fn.AddSum = function (cols: Array<number>, title: string, skipStep: number): JQuery {
        var tbody = $(this);
        var table = tbody.parent();
        var tfoot = $("<tr>");
        if (!skipStep) skipStep = 1;

        var trs = table.find("thead tr:eq(0) th").length;
        tfoot.html("");
        $("<th>{0}</th>".format(title ? title : "合计")).appendTo(tfoot);
        for (var i = 1; i < trs; i++) {
            $("<th>&nbsp;</th>").appendTo(tfoot);
        }

        $.each(cols, (i: number, o: any) => {
            var sum = 0;
            var tdIndex = -1;
            var fixed = 2;
            if (typeof (o) == "number") {
                tdIndex = o;
            } else {
                tdIndex = o[0];
                fixed = o[1];
            }

            tbody.find("tr").each(function (trindex) {
                if (trindex % skipStep !== 0) return true;
                var td = $(this).find(`td:eq(${tdIndex})`);
                var istablesaw = td.find("span.tablesaw-cell-content").length > 0;
                var value = istablesaw ? td.find("span.tablesaw-cell-content").text() : td.text();
                $.each(value.split("\n"), (index, str) => {
                    if (str) {
                        var num = parseFloat(str);
                        if (!isNaN(num)) sum += num;
                    }
                });
                return true;
            });
            tfoot.appendTo(tbody);
            tfoot.find(`th:eq(${tdIndex})`).text(sum.toFixed(fixed));

        });
        return tfoot;
    }


    $.fn.Display = function (isShow: boolean): JQuery {
        var $this = $(this);
        if (isShow) $this.show();
        else $this.hide();
        return $this;
    }


    $.fn.MakeHead = function (heads: Array<ITHead | string>) {
        $(this).empty();
        var tr = $("<tr></tr>").appendTo(this);
        try {
            $.each(heads, function (i: number, v: ITHead | string) {
                var $th = $("<th>").appendTo(tr);
                if (typeof (v) === "string")
                    $th.text(<string>v);
                else {
                    if ((<ITHead>(v)).name) $th.html((<ITHead>(v)).name);
                    if ((<ITHead>(v)).class) $th.addClass((<ITHead>(v)).class);
                    if ((<ITHead>(v)).width) $th.width((<ITHead>(v)).width);
                }
            });
        }
        catch (err) {
            console.log(err);
        }
        return this;
    };

    //$.fn.MakeHead = function (heads: Array<ITHead>, widths?: Array<number>) {
    //    $(this).empty();
    //    var tr = $("<tr></tr>").appendTo(this);
    //    $.each(heads, (i, v) => {
    //        var $th = $("<th>").appendTo(tr);

    //        try { if (widths && widths[i] > 0) $th.width(widths[i]); }
    //        catch (err) { }

    //        if (typeof (v) === "string") {
    //            var str: string = v.toString();
    //            $th.text(str);
    //        }
    //        else {
    //            if (v.name)
    //                $th.text(v.name);
    //            if (v.class)
    //                $th.addClass(v.class);
    //            if (v.width)
    //                $th.width(v.width);
    //        }
    //    });
    //    return this;
    //};

    //const clickOrTouch: string = (("ontouchend" in window)) ? "touchend" : "click";

    //$.fn.ClickOrTouch = function (target: string, act: any) {
    //    var $this = $(this);
    //    $this.on(clickOrTouch, target, act);
    //    return $this;
    //};


    ///设置弹出日期控件
    $.fn.SetDate = function () {
        $(this).on("focus", () => {
            WdatePicker({
                lang: "zh-cn",
                skin: "default",
                onpicked() {
                    $(this).blur();
                    $(this).change();
                },
                oncleared() {
                    $(this).blur();
                    $(this).change();
                }
            });
        }).prop("readonly", true);
        return this;
    }

    $.fn.SetDateTime = function () {
        $(this).on("focus", () => {
            WdatePicker({
                dateFmt: "yyyy-M-d HH:mm:ss",
                minDate: "%y-%M-%d 08:mm:ss",
                lang: "zh-cn",
                skin: "whyGreen",
                onpicked() {
                    $(this).blur();
                    $(this).change();
                },
                oncleared() {
                    $(this).blur();
                    $(this).change();
                }
            });
        }).prop("readonly", true);
        return this;
    };

    /**
     * 初始化表单
     * @returns
     */
    $.fn.initForm = function () {
        var form = $(this);
        form.find("input.date:enabled").SetDate();
        form.find("input.datetime:enabled").SetDateTime();

        form.find("select.ajaxSelect").each(function () {
            $(this).ajaxAddOptions();
        });
        $(".dateSwitch").each((i, o) => {
            $(o).DateSwitch();
        });
        form.trigger("after.InitForm");
        return form;
    };
    /**
     * 重置表单
     * @returns
     */
    $.fn.ResetForm = function () {
        var form = $(this);
        form.find("textarea,input:not([type=radio], [type=checkbox])").val("").trigger("change");
        form.find("input[type=checkbox],input[type=radio]").prop("checked", false).trigger("change");
        form.find(".has-error").removeClass("has-error");

        form.find("input,textarea").each(function () {
            var $this = $(this);
            var defaultValue = $this.data("defaultvalue");
            ///通过文本赋值默认值
            if (defaultValue != undefined) $this.val(defaultValue);
            else $this.val("");
            $this.trigger("change");
        });
        form.find("select").each(function () {
            var $this = $(this);
            var defaultValue = $this.data("defaultvalue");
            if (defaultValue != undefined) $this.val(defaultValue);
            else $this.val($(this).find("option:eq(0)").val()).trigger("change");
        });
        $("body").trigger("after.ResetForm", form);
        return form;
    }

    $.fn.tagName = function () {
        return this.prop("tagName");
    }

    /**
     * 序列化表单
     * @returns
     */
    $.fn.GetJson = function (after?: Function) {
        var model: Object = {};
        const form = $(this);
        const items = form.find("input,textarea,select");
        items.each(function () {
            const obj = $(this);
            var name = obj.prop("name");
            const id = obj.prop("id");
            if (!id || id.indexOf("s2id_") === 0) return true;
            if (!name) {  //若没有name则加上name
                name = id;
                obj.prop("name", name);
            };
            return true;
        });
        var o = items.serializeArray();

        for (let i in o) {
            if (o.hasOwnProperty(i)) {
                var name = o[i].name;
                var value = o[i].value;
                if (typeof (model[name]) == "undefined")
                    model[name] = value;
                else model[name] += `,${value}`;
            }
        }

        for (let p in model) {
            if (model.hasOwnProperty(p)) {
                model[p] = $.trim(model[p]);
            }
        }

        form.find("input[type=checkbox][data-valuetype=bool]").each(function (index, obj) {
            var checkbox = $(this);
            var id = checkbox.prop("id");
            model[id] = checkbox.is(":checked");
        });

        if (after) after(form, model);
        form.trigger("after.GetJson", [model, form]);
        return model;
    }

    /***
    *添加options
    *
    */
    $.fn.AddOptions = function (data: Array<any>, defaulttext?: string, defaultvalue?: string, setting?: any) {
        var set = $.extend({ key: "Key", value: "Value" }, setting);
        var $select = $(this);
        var optStr = "<option>";
        if (!defaultvalue) defaultvalue = "";
        $select.empty();
        if (defaulttext) $(optStr).val(defaultvalue).text(defaulttext).appendTo($select);
        $.each(data, (i, o) => {
            $(optStr).val(o[set.key]).text(set.value).appendTo($select).data(o);
        });
    }

    /**
     * 
     * @param {string} url?
     * @param {string} id?
     * @param {string} text?
     * @param {string} defaultId?
     * @param {string} defaultText?
     * @param {Function} init?
     * @returns
     */
    $.fn.ajaxAddOptions = function (url?: string, id?: string, text?: string, defaultId?: string, defaultText?: string) {
        var item = $(this);
        var $this = item;
        if (!url) url = $this.data("url");
        if (!url) return item;

        if (url.indexOf("/") !== 0) url = $.SailConfig.ApiRoot + url;

        if (!id) {
            id = $this.data("value") || "id";
            text = $this.data("text") || "Name";
            defaultId = $this.data("defaultvalue");
            defaultText = $this.data("defaulttext");
        };

        var optstr = "<option value='{0}'>{1}</<option>";
        item.empty();
        if (defaultText) item.append(optstr.format(defaultId, defaultText));

        $.ajax({
            //async: false,
            url: url,
            success: json => {
                if (json.IsSuccess) {
                    $(json.Data).each((index: any, element: any) => {
                        var option = $(optstr.format(element[id], element[text]));
                        option.data("item", element);
                        item.append(option);
                    });
                    item.trigger("ajax.Done", json.Data);
                }
            }
        });
        return item;
    };

    /**
     * 关闭自定义弹窗
     */
    $.fn.closeModal = function () {
        $("#modal_overlay").fadeOut(200);
        $(this).trigger("hidden.bs.modal");
        $(this).hide();
    };

    /**
     * 兼容bootstrap弹窗插件 
     * @param options
     */
    $.fn.myModal = function (options?: string) {
        var modal = $(this);
        var overlay = $("#modal_overlay");
        if (overlay.length === 0) {
            $("body").append($("<div id='modal_overlay'></div>"));
            overlay = $("#modal_overlay");
        }
        switch (options) {
            case "hide":
                modal.closeModal();
                break;
            default:
                modal.off("click", "[aria-hidden=true]")
                    .on("click", "[aria-hidden=true]", () => {
                        modal.closeModal();
                    });
                overlay.css({ display: "block", opacity: 0 });
                overlay.fadeTo(100, 0.6);
                modal.fadeTo(100, 1);
        }
    };

    /**
     * 双向绑定工具
     * @param {type} object
     * @returns
     */
    $.fn.ItemBinder = function (object?: Object): Binder {
        var $this = $(this);

        var binder: Binder = $this.data("binder");
        if (!binder) {
            binder = new Binder($(this), object);
            $this.data("binder", binder);
        }
        if (object) binder.SetObject(object);
        return binder;
    }


    //验证表单
    $.fn.CheckValidation = function () {
        var r = $(this).validationEngine({ returnIsValid: true });
        return r;
    }

    /*回车触发按钮的点击*/
    $.fn.EnterToClick = function (btn: any) {
        $(this).keydown((event) => {
            if (event.keyCode === 13) $(btn).click();
        });
        return this;
    }

    //给表格中的空白单元格加上一个空格
    $.fn.TableChange = function () {
        var $this = $(this);
        $this.find("td").each((i, o) => {
            if (!$(o).html()) $(o).html("&nbsp;");
        });
        return $this;
    }

    //根据src的路径获取远程脚本内容,或直接返回内部的html元素
    $.fn.loadRemoteTmpl = function () {
        var $this = $(this);
        var html = $this.html();
        if (!html || !html.trim()) {
            if ($this.prop("src")) {
                $.ajax({
                    url: $this.prop("src"),
                    async: false,
                    cache: false,
                    success: template => { $this.html(template); }
                });
            }
        }
        return $this;
    }


    //绑定模板和数据
    $.fn.Link = function (tmpl: string, data: any): JQuery {
        if (!$.isArray(data)) data = [data];
        $.Loadtmpl(tmpl).link(this, data);
        if ($.fn.tooltip) $(this).find("[data-toggle=tooltip]").tooltip();
        return $(this).TableChange();
    }

    //用模板和数据生成html
    $.fn.Render = function (tmpl: string, data: any): JQuery {
        if (!$.isArray(data)) data = [data];
        if ($.fn.tooltip) $(this).find("[data-toggle=tooltip]").tooltip();
        $(this).html($.Loadtmpl(tmpl).render(data));
        return $(this).TableChange();
    }

    //增加日期选择方式
    $.fn.DateSwitch = function () {
        var $this = $(this);
        var $ipts = $this.find("input[type=text]");
        var $start = $ipts.eq(0);
        var $end = $ipts.eq(1);
        var dayFormat = "yyyy-MM-dd";

        [".today", ".thisWeek", ".thisMonth", ".preDay", ".nextDay", ".preWeek", ".nextWeek", ".preMonth", ".nextMonth"].forEach(x => {
            $this.off("click", x);
        });
        $this.on("click", ".today", () => { //本日
            var date = new Date().format(dayFormat);
            $start.val(date);
            $end.val(date);
        }).on("click", ".thisWeek", () => { //本周
            $start.val(new Date().WeekFirst().format(dayFormat));
            $end.val(new Date().WeekEnd().format(dayFormat));

        }).on("click", ".thisMonth", () => { //本月
            $start.val(new Date().MonthFirst().format(dayFormat));
            $end.val(new Date().MonthEnd().format(dayFormat));
        }).on("click", ".preDay", () => { //上一天
            if (!$start.val()) $start.val(new Date().format(dayFormat));
            var date = DateTime.Parse($start.val()).AddDays(-1).format(dayFormat);
            $start.val(date);
            $end.val(date);
        }).on("click", ".nextDay", () => { //下一天
            if (!$start.val()) $start.val(new Date().format(dayFormat));
            var date = DateTime.Parse($start.val()).AddDays(1).format(dayFormat);
            $start.val(date);
            $end.val(date);
        }).on("click", ".preWeek", () => { //上一周
            if (!$start.val()) $start.val(new Date().format(dayFormat));
            var date = DateTime.Parse($start.val()).WeekFirst().AddDays(-7);
            $start.val(date.format(dayFormat));
            $end.val(date.WeekEnd().format(dayFormat));
        }).on("click", ".nextWeek", () => { //下一周
            if (!$start.val()) $start.val(new Date().format(dayFormat));
            var date = DateTime.Parse($start.val()).WeekFirst().AddDays(7);
            $start.val(date.format(dayFormat));
            $end.val(date.WeekEnd().format(dayFormat));
        }).on("click", ".preMonth", () => { //上一月
            if (!$start.val()) $start.val(new Date().format(dayFormat));
            var date = DateTime.Parse($start.val()).MonthFirst().AddMonths(-1);
            $start.val(date.format(dayFormat));
            $end.val(date.MonthEnd().format(dayFormat));
        }).on("click", ".nextMonth", () => { //下一月
            if (!$start.val()) $start.val(new Date().format(dayFormat));
            var date = DateTime.Parse($start.val()).MonthFirst().AddMonths(1);
            $start.val(date.format(dayFormat));
            $end.val(date.MonthEnd().format(dayFormat));
        });
        var isInit = $this.data("init");
        if (isInit !== false)
            $this.find(".thisMonth").click();
        return $this;
    }

    $.fn.InitLogin = function (set: ILoginSet) {
        var $this = $(this);
        var settings: ILoginSet = $.extend({
            inputId: "#LoginId",
            inputPwd: "#Password",
            ckRember: "#ckRemember",
            btnLogin: "#btnLogin",
            cookieName: "_LoginId"
        }, set);
        var $loginId = $this.find(settings.inputId);
        var $Password = $this.find(settings.inputPwd);
        var $ckRemember = $this.find(settings.ckRember);
        var $btnLogin = $this.find(settings.btnLogin);
        var cookieName = settings.path + settings.cookiesName;

        $loginId.focus();
        $Password.EnterToClick($btnLogin);
        var loginId = $.cookie(cookieName);

        if (loginId) {
            $ckRemember.attr("checked", true);
            $loginId.val(loginId);
            $Password.focus();
        }
        var api = new Sail.ApiHelper(settings.controller);

        $btnLogin.click(() => {
            api.get("login", { "": JSON.stringify($this.GetJson()) }, (result: any) => {
                if (!result.IsSuccess) {
                    ShowError(result.Msg);
                    return;
                }
                if ($ckRemember.is(":checked"))
                    $.cookie(cookieName, $loginId.val(), { expires: 30, path: settings.path });
                else
                    $.removeCookie(cookieName, { path: settings.path });
                window.location.href = settings.path;
            });
        });

    }

    //导出excel
    $.fn.Table2Excel = function (options: any) {
        var e = this;
        e.each(function () {
            if (!$.data(e, "plugin_table2excel")) {
                $.data(e, "plugin_table2excel", new Sail.ExportExcel(this, options));
            }
        });
        return e;
    }


    //导出excel的class
    export class ExportExcel {
        private element: any;
        private template: any;
        private tableRows: Array<any>;
        private settings: any;
        private uri: string;
        private defaults: any;

        constructor(element: any, options: any) {
            this.element = element;
            this.defaults = {
                exclude: ".noExl",
                name: "Table2Excel"
            };
            this.settings = $.extend({}, this.defaults, options);
            this.init();
        }

        init() {
            var e = this;
            e.uri = "data:application/vnd.ms-excel;base64,";
            e.template = {
                head: "<html xmlns:o=\"urn:schemas-microsoft-com:office:office\" xmlns:x=\"urn:schemas-microsoft-com:office:excel\" xmlns=\"http://www.w3.org/TR/REC-html40\"><head><!--[if gte mso 9]><xml><x:ExcelWorkbook><x:ExcelWorksheets>",
                sheet: {
                    head: "<x:ExcelWorksheet><x:Name>",
                    tail: "</x:Name><x:WorksheetOptions><x:DisplayGridlines/></x:WorksheetOptions></x:ExcelWorksheet>"
                },
                mid: "</x:ExcelWorksheets></x:ExcelWorkbook></xml><![endif]--></head><body>",
                table: {
                    head: "<table>",
                    tail: "</table>"
                },
                foot: "</body></html>"
            };

            e.tableRows = [];

            // get contents of table except for exclude
            $(e.element).each((i, o) => {
                var tempRows = "";
                $(o).find("tr").not(this.settings.exclude).each((i, o) => {
                    tempRows += "<tr>" + $(o).html() + "</tr>";
                });
                this.tableRows.push(tempRows);
            });


            e.tableToExcel(e.tableRows, e.settings.name);
        }
        private ctx: any;

        format(s: any, c: any) {
            return s.replace(/{(\w+)}/g, (m: any, p: any) => c[p]);
        };

        base64(s: string) {
            return window.btoa(unescape(encodeURIComponent(s)));
        };

        getFileName(settings: any): string {
            return (settings.filename ? settings.filename : "table2excel") + ".xls";
        }

        tableToExcel(table: any, name: string) {
            var e = this;



            e.ctx = {
                worksheet: name || "Worksheet",
                table: table
            };

            let fullTemplate: string = e.template.head;

            if ($.isArray(table)) {
                for (let i in table) {
                    fullTemplate += e.template.sheet.head + "Table" + i + "" + e.template.sheet.tail;
                }
            }

            fullTemplate += e.template.mid;

            if ($.isArray(table)) {
                for (let i in table) {
                    fullTemplate += e.template.table.head + "{table" + i + "}" + e.template.table.tail;
                }
            }

            fullTemplate += e.template.foot;

            for (let i in table) {
                if (table.hasOwnProperty(i)) {
                    e.ctx["table" + i] = table[i];
                }
            }

            delete e.ctx.table;

            const link = e.uri + e.base64(e.format(fullTemplate, e.ctx));
            const a: any = document.createElement("a");
            a.download = e.getFileName(e.settings);
            a.href = link;
            a.click();
            return true;
        }
    }
};


$().ready(() => {
    $('body').initForm().validationEngine();
});
